
#ifndef _LEX_AN_H
#define _LEX_AN_H

#include <stdlib.h>
#include <string.h>
#include <stdio.h>

extern int Lmezery;

#define _Latom              0 // atom ve smyslu Q-systemu
#define _Latomovapromenna   1 // promenna pro atomy
#define _Lstromovapromenna  2 // promenna pro stromy
#define _Lseznamovapromenna 3 // promenna pro seznamy
#define _Llevazavorka       4 // (
#define _Lpravazavorka      5 // )
#define _Lcarka             6 // ,
#define _Lnul               7 // -NUL-
#define _Ldekompozice       8 // $$
#define _Lrovnost           9 // =
#define _Lnerovnost        10 // "
#define _Ldans             11 // -DANS-
#define _Lhors             12 // -HORS-
#define _Lplus             13 // +
#define _Lkopie            14 // --
#define _Lpodminka         15 // /
#define _Llomitko          15 // /
#define _Lprepis           16 // ==
#define _Ltecka            17 // .
#define _Lou               18 // -OU-
#define _Let               19 // -ET-
#define _Lnon              20 // -NON-
#define _Llevapodmzavorka  21 // (.
#define _Lpravapodmzavorka 22 // .)
#define _Lreq              23 // -REQ-
#define _Ldet              24 // -DET-
#define _Linv              25 // -INV-
#define _Lzarazka          26 // zarazka pro syntaktickou analyzu (konec vstupu)
#define _Lmaxtag           27 // odtud dal jsou cisla vrcholu
#define _Lmaxvrchol        (((((unsigned long)0)-1-_Lmaxtag)/10)*10)

class Lseznam
 {protected:
    Lseznam *dalsi;
    unsigned long rad,sl;
  public:
    Lseznam(unsigned long r, unsigned long s) {dalsi=NULL; rad=r; sl=s;};
    virtual ~Lseznam(void) {;};
    Lseznam *dal(void) {return dalsi;}; //vrati dalsi polozku seznamu
    void pridej(Lseznam *d) {dalsi=d;}; //dalsi polozku seznamu nahradi zadanou hodnotou
    virtual unsigned long tag(void)=0;  //vrati tag teto polozky
    virtual char *obsah(void)=0;        //vrati text ulozeny v polozce (tyka se atomu a promennych)
    unsigned long radek(void) {return rad;}
    unsigned long sloupec(void) {return sl;}
 };

class Latomicky
 {protected:
    unsigned int odkazu;
  public:
    Latomicky(void) {odkazu=1;};
    Latomicky *pridej(void) {odkazu++; return this;}; //prida odkaz na sebe (zvysi pocitadlo)
    virtual ~Latomicky(void) {;}
    void umaz(void) {if(!--odkazu) delete this;};     //umaze odkaz na sebe (snizi pocitadlo), nezbyva-li jiz zadny, smaze se
    virtual unsigned long tag(void)=0;                //vrati tag teto polozky
    virtual char *obsah(void)=0;                      //vrati text ulozeny v polozce (tyka se atomu a promennych)
 };

class Ltext:public Lseznam
 {protected:
    Latomicky *prvek;
  public:
    Ltext(Latomicky *p,unsigned int r, unsigned int s):Lseznam(r,s) {prvek=p;};
    virtual ~Ltext(void) {prvek->umaz();};
    virtual unsigned long tag(void) {return prvek->tag();};
    virtual char *obsah(void) {return prvek->obsah();};
 };

class Latom:public Latomicky
 {protected:
    char *jm;
  public:
    Latom(char *j):Latomicky() {jm=new char[strlen(j)+1];strcpy(jm,j);};
    virtual ~Latom(void) {delete[] jm;}
    virtual unsigned long tag(void) {return _Latom;};
    virtual char *obsah(void) {return jm;};
 };

class Latomovapromenna:public Latomicky
 {protected:
    char *jm;
  public:
    Latomovapromenna(char *j):Latomicky() {jm=new char[strlen(j)+1];strcpy(jm,j);};
    virtual ~Latomovapromenna(void) {delete[] jm;}
    virtual unsigned long tag(void) {return _Latomovapromenna;};
    virtual char *obsah(void) {return jm;};
 };

class Lstromovapromenna:public Latomicky
 {protected:
    char *jm;
  public:
    Lstromovapromenna(char *j):Latomicky() {jm=new char[strlen(j)+1];strcpy(jm,j);};
    virtual ~Lstromovapromenna(void) {delete[] jm;}
    virtual unsigned long tag(void) {return _Lstromovapromenna;};
    virtual char *obsah(void) {return jm;};
 };

class Lseznamovapromenna:public Latomicky
 {protected:
    char *jm;
  public:
    Lseznamovapromenna(char *j):Latomicky() {jm=new char[strlen(j)+1];strcpy(jm,j);};
    virtual ~Lseznamovapromenna(void) {delete[] jm;}
    virtual unsigned long tag(void) {return _Lseznamovapromenna;};
    virtual char *obsah(void) {return jm;};
 };

class Lkonstanta:public Lseznam
 {protected:
    int t;
  public:
    Lkonstanta(int tg,unsigned int r, unsigned int s):Lseznam(r,s) {t=tg;};
    virtual ~Lkonstanta(void) {;};
    virtual unsigned long tag(void) {return t;};
    virtual char *obsah(void) {fprintf(stderr,"CHYBA: Pozadavek vypisu pro lexikalni znacku.\r\n"); exit(-1); return NULL;};
 };

class Lvrchol:public Lseznam
 {protected:
    unsigned long cislo;
  public:
    Lvrchol(unsigned long n,unsigned int r, unsigned int s):Lseznam(r,s) {cislo=n;};
    virtual ~Lvrchol(void) {;};
    virtual unsigned long tag(void) {return cislo+_Lmaxtag;};
    virtual char *obsah(void) {fprintf(stderr,"CHYBA: Pozadavek vypisu pro lexikalni znacku.\r\n"); exit(-1); return NULL;};
 };

typedef char string[256];

class Lanstav //stav nacitani programu/vstupu
 {public:
    FILE *f;
    int tag,stav,zn;
    long zav,pzav;
    unsigned long rad,sl;
    Lanstav(FILE *fil);
    Lseznam *nacti_slovo_programu(void); //nacte jedno slovo programu ze souboru
    Lseznam *nacti_slovo_vstupu(void); //nacte jedno slovo vstupu ze souboru
  private:
    int cti_zn(void);
    void cti_id(string &s,int &p);
    void cti_jmzb(string &s,int &p);
    void cti_dvojty(string &s,int &p,int znak,int ztag);
    void cti_uvnitr(string &s,int &p);
 };


void smaz_Lseznam(Lseznam *l); //smaze seznam vstupnich slov
void test_Lseznamu(Lseznam*);
Lseznam* spoj_Lseznamy(Lseznam*,Lseznam*);

#endif